#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <libgen.h>
#include <dirent.h>
#include <pthread.h>
#include <semaphore.h>
#include <assert.h>
#include <ctype.h>

#include <arpa/inet.h>

#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/vfs.h>
#include <sys/mount.h>

#include <linux/unistd.h>
#include <linux/if.h>
#include <linux/wireless.h>

#include <net/route.h>

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include "bw_update_demo.h"
#include "getopt.h"
#include "bb_api.h"
#include "prj_rpc.h"
#include "pf_parser.h"
#include "util_api.h"

#define DBG_AR8030_GAP 3000
#define TX_PKT_TO  2000 /*uints:ms*/
#define TEST_TX_LEN 1024
#define HEAD_LEN 5
#define PAIR_TIMEOUT_DFT 100
#define FILE_NAME_LEN    255

#define MCS_CFG_DEFUALT  -2
#define MCS_CFG_AUTO     -1

#define PWR_CFG_DEFUALT  -2
#define PWR_CFG_AUTO     -1

#define BB_DELAY_HIST_NUM 64
#define BB_INTVL_HIST_NUM 32
#define BB_FRM_SIZE_HIST_NUM 50

#define MAX_RINGBUF_LEN  (1024*1024*2)

typedef enum
{
	CTRL_PLANE_PORT=0,
	DATA_PLANE_PORT,
    VIDEO_PLANE_PORT,
	PF_MAX_BB_PORT
}PF_BB_PORT_e;

bool is_reverse = false;
bool is_auto_send = false;  // 新增：自动发送模式标志（false=按Enter，true=定时1秒）

uint64_t total_tx_dat_len = 0;
uint32_t max_tx_data_len = 0;
uint32_t min_tx_data_len = 0xffffffff;
uint32_t tot_tx_pkt_num = 0;

uint64_t total_rx_dat_len = 0;
uint32_t total_rx_pkt_num = 0;

uint64_t total_tx_dat_len_g = 0;
uint32_t max_tx_data_len_g = 0;
uint32_t min_tx_data_len_g = 0xffffffff;
uint32_t tot_tx_pkt_num_g = 0;
uint64_t total_tx_dat_len_payload_g = 0;
uint32_t tot_tx_pkt_num_payload_g = 0;

uint64_t total_rx_dat_len_g = 0;
uint32_t total_rx_pkt_num_g = 0;
extern uint64_t total_rx_dat_len_payload_g;
extern uint32_t total_rx_pkt_num_payload_g;

static Task_Info_t  tx_task_info;
static Task_Info_t  rx_task_info;

static PF_AR8030_TX_THREAD_PARAM_t g_stAr8030TxThread;
PF_AR8030_RX_THREAD_PARAM_t g_stAr8030RxThread;

static bb_dev_handle_t *bb_handle;
static int slot = 0;//-1;   //default slot 0
static int p_exit = 0;
static int signal_exit = 0;
static int bb_skt_fd;
static test_tx_len = TEST_TX_LEN;
static int socket_port = VIDEO_PLANE_PORT;
static char filename[FILE_NAME_LEN] = {0};
static FILE *fp = NULL;
static int file_len = 0;
static int loop_times = 1;

static unsigned char HEADATA[5]={0x00,0x00,0x00,0x01,0x80};

void bw_update_demo_Usage(char * name)
{
    printf("Usage: %s [options]\n", name);
    printf("Options:\n");
    printf("\t-h       Print help info \n");
    printf("\t-d       DEV mode\n");
    printf("\t-a       AP mode\n");
    printf("\t-s       Slot id\n");
    printf("\t-r       Do pair first\n");
    printf("\t-j       just Do pair \n");
    printf("\t-t       Pair timeout(unit:s)\n");
    printf("\t-A       Asyn mode\n");
    printf("\t-b       Bandwidth,refers to bb_bandwidth_e\n");
    printf("\t-y       Enable Frame change\n");
    printf("\t-m       MCS, refers to bb_phy_mcs_e. -1 means auto.\n");
    printf("\t-l       Tx frame payload length\n");
    printf("\t-o       Buffer size\n");
    printf("\t-c       Test time(unit:s) for tx\n");
    printf("\t-R       Test from dev to ap\n");
    printf("\t-P       Set power, -1 means auto\n");
    printf("\t-f       Path of H264 file for transmit.\n");
    printf("\t-p       Port of the socket\n");
    printf("\t-L       Loop times of sending file\n");
    printf("\t-n       zi_dong_fa_song or fei_zi_dong_fa_song\n");

}

void pair_cb(void* arg, void* user)
{
    bb_event_pair_result_t *event = (bb_event_pair_result_t *)arg;
    uint8_t* slot_id = (uint8_t*)user;

    printf("pair ret %d slot_id %d\n", event->ret, *slot_id);
    switch (event->ret) {
        case -2:
            printf("pair timeout!\n");
            break;
        case 0:
            printf("pair ok!\n");
            break;
        default:
            break;
    }

    p_exit = 1;
}

static void signal_hander(uint32_t signal)
{
    char name[64];
    bb_set_prj_dispatch_in_t set_prj;
	prj_rpc_hdr_t *hdr;
	prj_cmd_event_pair_t *event_pair;

    if(signal_exit == 0)
    {
        printf("__Application will exit by signal:%d, pid:%d\n", signal, getpid());

        /*stop the pair*/
        hdr=(prj_rpc_hdr_t *)set_prj.data;
        hdr->cmdid = PRJ_CMD_EVENT_PAIR_STOP;

        bb_ioctl(bb_handle, BB_SET_PRJ_DISPATCH, &set_prj, NULL);

        if (signal == SIGSEGV)
        {
            SIG_DFL(signal);
        }

        signal_exit = 1;
    }
}

uint64_t MID_UTIL_Get_Time_ms(void)
{
    struct timeval tv;
	uint64_t ts_ms;
    gettimeofday(&tv, NULL);
	ts_ms = (uint64_t)tv.tv_sec*1000 + tv.tv_usec/1000;
    return ts_ms;
}

void PF_Add_Sync_Head(PF_BB_SYNC_PKT_t *sync_data, int data_len, unsigned char type, \
								unsigned int devid, unsigned char user)
{
	sync_data->sync_head[0]=0x00;
	sync_data->sync_head[1]=0x00;
	sync_data->sync_head[2]=0x00;
	sync_data->sync_head[3]=0x01;
	sync_data->sync_head[4]=0x80;
	//data len
	sync_data->sync_head[5]=(data_len)>>0;
	sync_data->sync_head[6]=(data_len)>>8;
	sync_data->sync_head[7]=(data_len)>>16;
	sync_data->sync_head[8]=(data_len)>>24;
	//sync_id
	sync_data->sync_head[9]+=1;
	//type
	sync_data->sync_head[10]=type;
	//devid
	sync_data->sync_head[11]=devid>>0;
	sync_data->sync_head[12]=devid>>8;
	sync_data->sync_head[13]=devid>>16;
	sync_data->sync_head[14]=devid>>24;
	//user
	sync_data->sync_head[15]=user;
}


void * PF_AR8030_Task_TX_For_Enter(void * args)
{
    char achName[64] = {0};
    int32_t s32Ret = 0;

    uint8_t *buffer;
    uint8_t *sendbuffer;

    int wr_len;
    PF_BB_SYNC_PKT_t bb_pkt;
    int32_t synclen = SYNC_HEADLEN;

    int sendlen;
    void * sedndata;

    unsigned char soc_id=0;
    uint64_t tx_ts;
    unsigned char slot_id = BB_SLOT_0;

    g_stAr8030TxThread.status = TASK_STATUS_RUNNING;

    soc_id = tx_task_info.soc_id;
    slot_id = tx_task_info.slot_id;
    
    //set thread name
    sprintf(achName, "BBTx_Task");
    prctl(PR_SET_NAME, achName, 0, 0, 0);

    buffer=(uint8_t *)malloc(FRAME_MAX_LEN);
    if (!buffer) {
        PRINT_ERR("malloc failed!");
        goto done;
    }

    sendbuffer=(uint8_t *)malloc(FRAME_MAX_LEN);
    if (!sendbuffer) {
        PRINT_ERR("malloc failed!");
        goto done;
    }

    if (!fp) {
        /* Fulfill with test data */
        memset(buffer, 0xCD, FRAME_MAX_LEN);
    }
    else {
        if (loop_times == 0) {
            goto done;
        }

        if(0 != fseek(fp, 0, SEEK_SET)) {
            PRINT_ERR();
            goto done;
        }
    }

    PRINT_TRACE("start %s\n",__func__);
    if (is_auto_send) {
        printf("开始自动发送数据,每隔1秒发送一次...\n");
    } else {
        printf("按Enter键发送数据(或 'q' 退出)...\n");
    }
    while(1)
    {
        // 线程退出逻辑
        if(g_stAr8030TxThread.s32Ar8030TxThreadExit)
        {
            if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING_2) {
                PRINT_ERR("exit %s",__func__);
                break;
            }
            g_stAr8030TxThread.status = TASK_STATUS_SHUTTING;
        }

        // 线程暂停逻辑
        if(g_stAr8030TxThread.s32sAr8030TxThreadSuspend)
        {
            PRINT_ERR("suspend %s",__func__);
            usleep(500*1000);
            continue;
        }

        if (!is_auto_send) {
            // 手动模式：等待用户输入
            char input = getchar();
            if (input == 'q' || input == 'Q') {
                g_stAr8030TxThread.s32Ar8030TxThreadExit = true;
                g_stAr8030TxThread.status = TASK_STATUS_SHUTTING;
                continue;
            } else if (input != '\n') {
                // 忽略非Enter键输入
                continue;
            }
        } else {
            // 自动模式：无需输入，直接进入发送流程
            // （定时逻辑在发送后处理）
        }
        //数据发送逻辑
        sendlen = 0;
        if (fp) {
            wr_len = fread(buffer, 1, test_tx_len, fp);
            if (wr_len != test_tx_len) {
                if (loop_times != -1) {
                    loop_times--;
                    if (loop_times == 0) {
                        g_stAr8030TxThread.s32Ar8030TxThreadExit = true;
                        g_stAr8030TxThread.status = TASK_STATUS_SHUTTING;
                    }
                    else {
                        fseek(fp, 0, SEEK_SET);
                    }
                }
                else {
                    fseek(fp, 0, SEEK_SET);
                }
            }

            sendlen = wr_len;
            sedndata = (void *)buffer;
        }
        else {
            //build bb pkt
            if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING) {
                PF_Add_Sync_Head(&bb_pkt,wr_len,EVENT_BB_STOP_TEST,soc_id,0);
            }
            else {
                PF_Add_Sync_Head(&bb_pkt,wr_len,EVENT_BB_SEND_DATA,soc_id,0);
            }
            wr_len = test_tx_len;

            memcpy(bb_pkt.data, buffer, wr_len);

            sendlen = synclen + wr_len;
            sedndata = (void *)&bb_pkt;
        }

        if (sendlen) {
            // Print packet info before sending
            printf("\nPreparing to send [%d bytes]: ", sendlen);
            for (int i = 0; i < ((sendlen < 32) ? sendlen : 32); i++) {
                printf("%02X ", ((uint8_t *)sedndata)[i]);
            }
            if (sendlen > 32) printf("...");
            printf("\n");

            int have_sent = 0;
            tx_ts = MID_UTIL_Get_Time_ms();
            int init_dat_len = sendlen;
            
            while((sendlen > 0) && (MID_UTIL_Get_Time_ms()-tx_ts < TX_PKT_TO))
            {
                int sentcnt = bb_socket_write(bb_skt_fd, &((uint8_t *)sedndata)[have_sent], sendlen, WRITE_TIMEOUT);
                if(sentcnt > 0) {
                    printf("Sent %d bytes (total %d/%d)\n", sentcnt, have_sent + sentcnt, init_dat_len);
                    sendlen -= sentcnt;
                    have_sent += sentcnt;
                }
                else {
                    PRINT_ERR("bb_socket_write fail, ret=%d, have_sent=%d, remaining=%d", 
                            sentcnt, have_sent, sendlen);
                    usleep(100);
                }
            }
            //自动模式下添加1秒延迟
 	     if (is_auto_send && !g_stAr8030TxThread.s32Ar8030TxThreadExit) {
            sleep(1);  // 每隔1秒发送一次
            }


           if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING) {
               g_stAr8030TxThread.status = TASK_STATUS_SHUTTING_2;
           }
           
        }

    }

done:
    PRINT_ERR("done");
    if (buffer) {
        free(buffer);
    }

    if (sendbuffer) {
        free(sendbuffer);
    }

    bb_socket_close(bb_skt_fd);

    g_stAr8030TxThread.status = TASK_STATUS_SHUTDOWN;

    return NULL;
}

void * PF_AR8030_Task_TX(void * args)
{
    char achName[64] = {0};
    int32_t s32Ret = 0;

	uint8_t *buffer;
	uint8_t *sendbuffer;

	int wr_len;
	PF_BB_SYNC_PKT_t bb_pkt;
	int32_t synclen = SYNC_HEADLEN;

	int sendlen;
	void * sedndata;

	uint64_t pretime=0,nowtime=0;
	int sentcnt =0;
	int have_sent=0;
	int init_dat_len=0;
	unsigned char soc_id=0;
	uint64_t tx_ts;
	unsigned char slot_id = BB_SLOT_0;

    g_stAr8030TxThread.status = TASK_STATUS_RUNNING;

	soc_id = tx_task_info.soc_id;
	slot_id = tx_task_info.slot_id;
	//set thread name
	sprintf(achName, "BBTx_Task");
    prctl(PR_SET_NAME, achName, 0, 0, 0);

	buffer=(uint8_t *)malloc(FRAME_MAX_LEN);
    if (!buffer) {
        PRINT_ERR("malloc failed!");
        goto done;
    }

	sendbuffer=(uint8_t *)malloc(FRAME_MAX_LEN);
    if (!sendbuffer) {
        PRINT_ERR("malloc failed!");
        goto done;
    }

    if (!fp) {
        /* Fulfill with test data */
        memset(buffer, 0xCD, FRAME_MAX_LEN);
    }
    else {
        if (loop_times == 0) {
            goto done;
        }

        if(0 != fseek(fp, 0, SEEK_SET)) {
            PRINT_ERR();
            goto done;
        }
    }

	PRINT_TRACE("start %s\n",__func__);
	while(1)
	{
        sendlen = 0;
		if(g_stAr8030TxThread.s32Ar8030TxThreadExit )
		{
            if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING_2) {
                PRINT_ERR("exit %s",__func__);
                break;
            }
            g_stAr8030TxThread.status = TASK_STATUS_SHUTTING;
		}
		if(g_stAr8030TxThread.s32sAr8030TxThreadSuspend)
		{
			PRINT_ERR("suspend %s",__func__);
			usleep(500*1000);
			continue;
		}

        if (fp) {
            wr_len = fread(buffer, 1, test_tx_len, fp);


            if (wr_len != test_tx_len) {
                if (loop_times != -1) {
                    loop_times--;
                    if (loop_times == 0) {
                        g_stAr8030TxThread.s32Ar8030TxThreadExit = true;
                        g_stAr8030TxThread.status = TASK_STATUS_SHUTTING;
                    }
                    else {
                        fseek(fp, 0, SEEK_SET);
                    }
                }
                else {
                    fseek(fp, 0, SEEK_SET);
                }
            }

            sendlen = wr_len;
            sedndata = (void *)buffer;
        }
        else {
            //build bb pkt

            if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING) {
                printf("Tx task shutting down!!\n");
                PF_Add_Sync_Head(&bb_pkt,wr_len,EVENT_BB_STOP_TEST,soc_id,0);
            }
            else {
                PF_Add_Sync_Head(&bb_pkt,wr_len,EVENT_BB_SEND_DATA,soc_id,0);
            }
		    wr_len = test_tx_len;

            memcpy(bb_pkt.data, buffer, wr_len);

            sendlen = synclen + wr_len;
            sedndata = (void *)&bb_pkt;
        }

        if (sendlen) {
            /*stats*/
            if(true)
            {
                if(sendlen > max_tx_data_len)
                {
                    max_tx_data_len = sendlen;
                    max_tx_data_len_g = sendlen;
                }
                if(sendlen < min_tx_data_len)
                {
                    min_tx_data_len = sendlen;
                    min_tx_data_len_g = sendlen;
                }
                total_tx_dat_len += sendlen;
                total_tx_dat_len_g += sendlen;

                tot_tx_pkt_num++;
                tot_tx_pkt_num_g++;
                if (g_stAr8030TxThread.status != TASK_STATUS_SHUTTING) {
                    total_tx_dat_len_payload_g += wr_len;
                    tot_tx_pkt_num_payload_g++;
                }
                nowtime = MID_UTIL_Get_Time_ms();
                if(nowtime-pretime > DBG_AR8030_GAP)
                {
                    bb_get_mcs_in_t in = { 0 };
                    bb_get_mcs_out_t mcs_out;
                    int ret;
                    in.dir = BB_DIR_TX;
                    in.slot = slot_id;
                    ret = bb_ioctl(bb_handle, BB_GET_MCS, &in, &mcs_out);
                    if(ret)
                    {
                        PRINT_ERR("get bb mcs fail,ret=%d",ret);
                    }

                    PRINT_INFO("tx data rate =%d kbps,tot_tx_pkt_num=%d mcs %d tp %lu kbps\n",
                        total_tx_dat_len*8/(nowtime-pretime),
                        tot_tx_pkt_num,
                        mcs_out.mcs,
                        mcs_out.throughput);

                    PF_link_status_print(is_reverse?slot_id:BB_USER_BR_CS);
                    printf("#######################################################\n\n");

                    pretime= nowtime;
                    total_tx_dat_len=0;
                    max_tx_data_len = 0;
                    min_tx_data_len = 0xfffffff;
                    tot_tx_pkt_num = 0;
                }
            }

            sentcnt =0;
            have_sent=0;
            tx_ts = MID_UTIL_Get_Time_ms();
            init_dat_len = sendlen;
            while((sendlen>0) &&(MID_UTIL_Get_Time_ms()-tx_ts < TX_PKT_TO))
            {
                sentcnt = bb_socket_write(bb_skt_fd, &sedndata[have_sent], sendlen, WRITE_TIMEOUT);
                if(sentcnt >0){
                            printf("Send Data [%d bytes]: ", sentcnt);
                            for (int i = 0; i < sentcnt && i < 32; i++) {
                                printf("%02X ", ((uint8_t *)&sedndata[have_sent])[i]);
                            }
                            if (sentcnt > 32) printf("...");
                            printf("\n");



                    sendlen = sendlen-sentcnt;
                    have_sent +=sentcnt;
                  //  printf("bb_socket_write success----");
                    sleep(1);
                }
                else{
                    PRINT_ERR("bb_socket_write%d : write  fail,ret=0x%x,have_sent=%d,sendlen=%d,init_dat_len=%d,tx_ts=%llu,ts=%llu",
                        bb_skt_fd,
                        sentcnt,have_sent,sendlen,init_dat_len,tx_ts,MID_UTIL_Get_Time_ms());
                    usleep(100);
                }
            }
            if(sendlen > 0)
            {
                PRINT_ERR("bb_socket_write timeout,remain=%d",sendlen);
            }
        }

        if (g_stAr8030TxThread.status == TASK_STATUS_SHUTTING) {
            g_stAr8030TxThread.status = TASK_STATUS_SHUTTING_2;
        }
	}

done:
	PRINT_ERR("done");
    if (buffer) {
	    free(buffer);
    }

    if (sendbuffer) {
	    free(sendbuffer);
    }

	bb_socket_close(bb_skt_fd);

    g_stAr8030TxThread.status = TASK_STATUS_SHUTDOWN;

	return NULL;
}

void PF_AR8030_RX_Stats(uint8_t slot_id, uint8_t *data, unsigned int  data_len)
{
    static uint64_t pretime = 0, nowtime = 0;
    int ret;

    total_rx_dat_len += data_len;
    total_rx_pkt_num++;

    total_rx_dat_len_g += data_len;
    total_rx_pkt_num_g++;

    nowtime = MID_UTIL_Get_Time_ms();
    if(nowtime - pretime > DBG_AR8030_GAP)
    {
        bb_get_mcs_in_t in = { 0 };
        bb_get_mcs_out_t mcs_out;
        in.dir = BB_DIR_RX;
        in.slot = slot_id;
        ret = bb_ioctl(bb_handle, BB_GET_MCS, &in, &mcs_out);
        if(ret)
        {
            PRINT_ERR("get bb mcs fail,ret=%d",ret);
        }

        PRINT_INFO("rx data rate =%d kbps,total_rx_pkt_num=%d mcs %d tp %lu kbps\n",
            total_rx_dat_len*8/(nowtime-pretime),
            total_rx_pkt_num,
            mcs_out.mcs,
            mcs_out.throughput);
        PF_link_status_print(is_reverse?slot_id:BB_USER_BR_CS);
        printf("#############################################################\n\n");

        pretime = nowtime;
        total_rx_dat_len=0;
        total_rx_pkt_num = 0;
    }
}

void init_event_data(void * arg,unsigned int len){
    msg_hdr_t * data = (msg_hdr_t*)arg;
    memcpy(data->sync_head,HEADATA,HEAD_LEN);
    data->channel=0;
    data->data_len=len;
    data->skip_next_frame_len=0;
    data->sync_id=0;
    data->is_stream=0;
	data->dev=0;
    data->type=EVENT_IDLE;
    data->user=0;
    data->data=(unsigned char*)malloc(len);
}

void * PF_AR8030_Task_RX(void * args)
{
	char achName[64] = {0};
	int32_t s32Ret = 0;
	int ret;
	uint8_t *buffer=(uint8_t *)malloc(FRAME_MAX_LEN);
	uint8_t soc_id = rx_task_info.soc_id;
	uint8_t slot_id = rx_task_info.slot_id;

	uint32_t len = FRAME_MAX_LEN;
	msg_hdr_t Rxntdata;

    g_stAr8030TxThread.status = TASK_STATUS_RUNNING;

	sprintf(achName, "BBRX_Task");
    prctl(PR_SET_NAME, achName, 0, 0, 0);

	init_event_data(&Rxntdata,FRAME_MAX_LEN);

	PRINT_TRACE("start,soc_id = %d slot_id=%d",soc_id,slot_id);
	while(1)
	{
        if(g_stAr8030RxThread.s32Ar8030RxThreadExit )
		{
			PRINT_ERR("exit");
            break;
        }

		if(g_stAr8030RxThread.s32sAr8030RxThreadSuspend){
			usleep(500*1000);
			continue;
		}

		ret = bb_socket_read(bb_skt_fd, buffer, len, READ_TIMEOUT);
		if(ret < 0)
		{
			usleep(100);
			PRINT_ERR("bb_socket_read error ret= %d\n",ret);
			continue;
		}
		else if(ret == 0)
		{
			continue;
		}else{
            printf("Recv Data [%d bytes]: ", ret);
            for (int i = 0; i < ret; i++)  
            {
              
                   printf("%02X ", (uint8_t)buffer[i]);
                
                
            }
            printf("\n======ret=%d,len=%d\n",ret,len);
        


            // 打印ASCII部分
            printf("ASCII: ");
            for (int i = 0; i < ret; i++) {
                // 只打印可显示字符(32-126)
                if (buffer[i] >= 32 && buffer[i] <= 126) {
                    printf("%c ", buffer[i]);
                } else {
                    printf(". ");  // 不可显示字符用点号代替
                }
                if ((i+1) % 16 == 0) {  // 每16字节换行
                    printf("\n      ");
                }
            }
            printf("\n===================\n");

        }





		PF_AR8030_RX_Stats(slot_id, buffer, ret);

	    Rxntdata.type=EVENT_IDLE;
	    Rxntdata.is_stream=1;
	    Rxntdata.data_len=ret;
	    Rxntdata.dev=0;
		Rxntdata.data = buffer;
        PF_Parser_On_Event(&Rxntdata);
	}

	// uninit_event_data(&Rxntdata);
	free(buffer);
	bb_socket_close(bb_handle);

    g_stAr8030RxThread.status = TASK_STATUS_SHUTDOWN;

	return NULL;
}

void PF_link_status_print(int slot)
{
    bb_get_status_in_t bb_st_in = {0};
    bb_get_status_out_t bb_st_out;

    bb_st_in.user_bmp = (1<<slot);
    bb_ioctl(bb_handle, BB_GET_STATUS, &bb_st_in, &bb_st_out);
    printf("[%d],role=%d,mode=%d,sync_mode=%d,sync_master=%d,cfg_sbmp=0x%0x,rt_sbmp=0x%0x\n",
        0,bb_st_out.role,bb_st_out.mode,
        bb_st_out.sync_mode,bb_st_out.sync_master,bb_st_out.cfg_sbmp,bb_st_out.rt_sbmp);

    printf("slot%d\n",slot);

    printf("dev_%d",0);
    printf("link_status:state=%d,rx_mcs=%d\n",
        bb_st_out.link_status[slot].state,bb_st_out.link_status[slot].rx_mcs);
    printf("user_status:tx_mcs=%d,tx_rf_mode=%d,tx_tintlv_enable=%d,tx_tintlv_len=%d,"
        "tx_tintlv_num=%d,tx_bw=%d,tx_freq=%lu kHz\n",
        bb_st_out.user_status[slot].tx_status.mcs,bb_st_out.user_status[slot].tx_status.rf_mode,
        bb_st_out.user_status[slot].tx_status.tintlv_enable,bb_st_out.user_status[slot].tx_status.tintlv_len,
        bb_st_out.user_status[slot].tx_status.tintlv_num,bb_st_out.user_status[slot].tx_status.bandwidth,
        bb_st_out.user_status[slot].tx_status.freq_khz);

    printf("user_status:rx_mcs=%d,rx_rf_mode=%d,rx_tintlv_enable=%d,rx_tintlv_len=%d,"
        "rx_tintlv_num=%d,rx_bw=%d,rx_freq=%lu kHz\n",
        bb_st_out.user_status[slot].rx_status.mcs,bb_st_out.user_status[slot].rx_status.rf_mode,
        bb_st_out.user_status[slot].rx_status.tintlv_enable,bb_st_out.user_status[slot].rx_status.tintlv_len,
        bb_st_out.user_status[slot].rx_status.tintlv_num,bb_st_out.user_status[slot].rx_status.bandwidth,
        bb_st_out.user_status[slot].rx_status.freq_khz);
}

int main(int argc, char ** argv)
{
	int s32Ret;
    bool is_ap = false;
    bool is_asyn = true;            // pair as async in default
    bool is_frame_change = false;
    bool is_tx = true;
    bool is_pair = false;
    bool just_pair = false;
    
    int exit_time = -1;
    int dev_num;
    int mcs = MCS_CFG_DEFUALT;
    int wait_times = 0;
    int bandwidth = 0;
    int buffer_size = 10*1024;
    int test_time = -1;
    int power = PWR_CFG_DEFUALT;
    bb_host_t* phost=NULL;
    bb_dev_t** devs=NULL;
    int32_t timeout = PAIR_TIMEOUT_DFT;
    uint32_t flag =BB_SOCK_FLAG_RX|BB_SOCK_FLAG_TX;
    bb_sock_opt_t sock_data_buf_size;
	bb_set_prj_dispatch_in_t set_prj;
	prj_rpc_hdr_t *hdr;
	prj_cmd_event_pair_t *event_pair;
    bb_event_callback pcb = (bb_event_callback)pair_cb;
    bb_set_event_callback_t cb;
    bb_set_frame_change_t bb_set_frame_change;
    bb_set_mcs_mode_t bb_set_mcs_mode;
    bb_set_mcs_t bb_set_mcs;
    bb_set_bandwidth_t bb_set_bandwidth;
    bb_set_pwr_auto_in_t bb_set_pwr_auto_in;
    bb_set_pwr_mode_in_t bb_set_pwr_mode_in;
    bb_set_pwr_in_t bb_set_pwr_in;
    int ret;
    uint64_t now_ms, start_ms;

    if(argc == 1){
	    bw_update_demo_Usage(argv[0]);
		return -1;
	}

    while((s32Ret = getopt(argc, argv, "hdas:t:Ae:ym:b:l:o:c:RP:f:p:rjL:n")) != -1)
    {
        switch(s32Ret)
		{
            case 'h':
                bw_update_demo_Usage(argv[0]);
                return 0;
            case 'd':
                printf("dev mode\n");
                is_ap = false;
                break;
            case 'a':
                printf("ap mode\n");
                is_ap = true;
                break;
            case 's':
                slot = atoi(optarg);
                printf("slot %d\n", slot);
                break;
            case 't':
                timeout = atoi(optarg);
                printf("timeout %d\n", timeout);
                break;
            case 'A':
                printf("is_asyn mode\n");
                is_asyn = true;
                break;
            case 'e':
                exit_time = atoi(optarg);
                printf("stop pair after %ds\n",exit_time);
                break;
            case 'y':
                is_frame_change = true;
                printf("frame change\n");
                break;
            case 'm':
                mcs = atoi(optarg);
                printf("mcs = %d\n",mcs);
                break;
            case 'b':
                bandwidth = atoi(optarg);
                printf("bandwidth = %d\n",bandwidth);
                break;
            case 'l':
                test_tx_len = atoi(optarg);
                printf("test_tx_len = %d\n",test_tx_len);
                break;
            case 'o':
                buffer_size = atoi(optarg);
                printf("buffer_size = %d\n",buffer_size);
                break;
            case 'c':
                test_time = atoi(optarg);
                printf("test_time = %d\n",test_time);
                break;
            case 'R':
                is_reverse = true;
                printf("reverse\n");
                break;
            case 'P':
                power = atoi(optarg);
                printf("power = %d\n",power);
                break;
            case 'f':
                strcpy(filename, optarg);
                printf("filename = %s\n",filename);
                break;
            case 'p':
                socket_port = atoi(optarg);
                printf("socket_port = %d\n",socket_port);
                break;
            case 'r':
                is_pair = true;
                printf("do pair\n");
                break;
            case 'j':
                just_pair = true;
                printf("just pair\n");
                break;            
            case 'L':
                loop_times = atoi(optarg);
                printf("loop_times = %d\n",loop_times);
                break;
            case 'n':
                is_auto_send = true;
                printf("启用自动发送模式,每隔1秒发送一次\n");
                break;
            default:
                PRINT_ERR("unknow cmd param !");
    			bw_update_demo_Usage(argv[0]);
                return -1;
        }
    }

    /* Open the file need to transmit */
    if (filename[0]) {
        fp = fopen(filename, "rb");
        if (fp == NULL) {
            PRINT_ERR("open %s failed!", filename);
            return 0;
        }

        if (0 != fseek(fp, 0, SEEK_END)) {
            fclose(fp);
            return -1;
        }

        file_len = ftell(fp);
    }

    if ((!is_reverse && is_ap) ||
        (is_reverse && !is_ap)) {
        is_tx = true;
    }
    else {
        is_tx = false;
    }

    printf("dir:%s\n",is_tx?"tx":"rx");

    printf("%s compiled at: %s %s\n", argv[0], __DATE__, __TIME__);

	if (is_ap && (slot == 255)) {
        PRINT_ERR("ap should assign the slot!");
        return -1;
    }

    /* ==================Build connection with 8030(start)================ */
    /* Connect to the daemon */
	s32Ret = bb_host_connect(&phost,"127.0.0.1",BB_PORT_DEFAULT);
	if(s32Ret)
	{
		PRINT_ERR("bb connect error,ret=%d",s32Ret);
		//bb_deinit();
		return -1;
	}

    /* get dev list of the 8030 */
    dev_num = bb_dev_getlist(phost,&devs);
    if (dev_num == 0) {
		PRINT_ERR("Get no device!");
		return -1;
    }

    /* Open the dev 8030 */
    bb_handle = bb_dev_open(devs[0]);
    if (!bb_handle) {
		PRINT_ERR("bb_dev_open error");
		//bb_deinit();
		return -1;
    }

    bb_dev_freelist(devs);

    /* Open the socket */
    sock_data_buf_size.rx_buf_size=10000;
    sock_data_buf_size.tx_buf_size=30000;
    // if(is_tx) {
    //     sock_data_buf_size.tx_buf_size=buffer_size;//40*1024;
    //     PRINT_ERR("is tx buffer_size=%d\n",buffer_size);
    // }
    // else {
    //     PRINT_ERR("is no tx buffer_size=%d\n",buffer_size);
    //     sock_data_buf_size.rx_buf_size=buffer_size;//40*1024;
    // }



    bb_skt_fd = bb_socket_open(bb_handle,
                               is_ap?slot:0,
                               socket_port,
                               flag,
                               &sock_data_buf_size);
    if (bb_skt_fd < 0) {
		PRINT_ERR("bb_socket_open error");
		//bb_deinit();
		return -1;
    }

    cb.callback = pcb;
    cb.event    = BB_EVENT_PAIR_RESULT;
    cb.user     = (void*)&slot;
    s32Ret = bb_ioctl(bb_handle, BB_SET_EVENT_SUBSCRIBE, &cb, 0);
    if (s32Ret) {
        PRINT_ERR("set callback err! ret = %d",s32Ret );
        return -1;
    }
    printf("Build connection with 8030 success!\n");
    /* ==================Build connection with 8030(end)================ */

    if (power == PWR_CFG_AUTO) {
        /* power auto */
        bb_set_pwr_auto_in.pwr_auto = 1;
        bb_ioctl(bb_handle, BB_SET_POWER_AUTO, &bb_set_pwr_auto_in, NULL);
    }
    else if (power >= 0) {
        /* power auto */
        bb_set_pwr_auto_in.pwr_auto = 0;
        bb_ioctl(bb_handle, BB_SET_POWER_AUTO, &bb_set_pwr_auto_in, NULL);

        /* power low */
        bb_set_pwr_in.usr = BB_USER_BR_CS;
        bb_set_pwr_in.pwr = power;
        bb_ioctl(bb_handle, BB_SET_POWER, &bb_set_pwr_auto_in, NULL);
    }

    if (is_pair) {
        /* begin to pair */
        hdr=(prj_rpc_hdr_t *)set_prj.data;
        hdr->cmdid=PRJ_CMD_EVENT_PAIR;
        event_pair = (prj_cmd_event_pair_t*)hdr->data;
        event_pair->bitmap = is_ap?(1 << slot):0;
        event_pair->timeout = timeout;
        event_pair->asyn = is_asyn;

        bb_ioctl(bb_handle, BB_SET_PRJ_DISPATCH, &set_prj, NULL);


        if (is_asyn) {
            signal(SIGINT, signal_hander);
        }

        /*wait for reult*/
        while (1) {
            if (!p_exit && !signal_exit) {
                printf("waiting for pair\n");
            }
            else {
                break;
            }

            if (exit_time == wait_times) {
                /*stop the pair*/
                hdr=(prj_rpc_hdr_t *)set_prj.data;
                hdr->cmdid = PRJ_CMD_EVENT_PAIR_STOP;

                bb_ioctl(bb_handle, BB_SET_PRJ_DISPATCH, &set_prj, NULL);
            }

            sleep(1);
            wait_times++;
        }

        if (signal_exit) {
            exit(0);
        }

        printf("==== pair success !!!\n");
    }

        if (just_pair) {
        return -1;
        exit(0);
        }




    if (is_ap && is_tx) {
        /* set frame change*/
        if (is_frame_change) {
            bb_set_frame_change.mode = 1;
        }
        else {
            bb_set_frame_change.mode = 0;
        }

        ret = bb_ioctl(bb_handle, BB_SET_FRAME_CHANGE, &bb_set_frame_change, NULL);
        printf("BB_SET_FRAME_CHANGE %d ret %d\n", bb_set_frame_change.mode, ret);
    }


    /* set bandwidth*/
    if (bandwidth) {
        bb_set_bandwidth.bandwidth = bandwidth;
        if (is_tx) {
            bb_set_bandwidth.dir = BB_DIR_TX;
        }
        else {
            bb_set_bandwidth.dir = BB_DIR_RX;
        }

        bb_set_bandwidth.slot = slot;
        ret = bb_ioctl(bb_handle, BB_SET_BANDWIDTH, &bb_set_bandwidth, NULL);
        printf("BB_SET_BANDWIDTH bandwidth %d ret %d\n", bandwidth, ret);
    }
   // return 0;
    /*set mcs*/
    if (mcs == MCS_CFG_AUTO) {
        bb_set_mcs_mode.auto_mode = true;
        bb_set_mcs_mode.slot = slot;
        s32Ret = bb_ioctl(bb_handle, BB_SET_MCS_MODE, (void*)&bb_set_mcs_mode, NULL);
        if (s32Ret) {
            PRINT_ERR("set mcs mode err! ret = %d",s32Ret );
            return -1;
        }
    }
    else if (mcs >= 0){
        bb_set_mcs_mode.auto_mode = false;
        bb_set_mcs_mode.slot = slot;
        s32Ret = bb_ioctl(bb_handle, BB_SET_MCS_MODE, (void*)&bb_set_mcs_mode, NULL);
        if (s32Ret) {
            PRINT_ERR("set mcs mode err! ret = %d",s32Ret );
            return -1;
        }

        bb_set_mcs.mcs = mcs;
        bb_set_mcs.slot = 0;
        s32Ret = bb_ioctl(bb_handle, BB_SET_MCS, (void*)&bb_set_mcs, NULL);
        if (s32Ret) {
            PRINT_ERR("set mcs err! ret = %d",s32Ret );
            return -1;
        }
    }

    // if (is_tx) {
    //     tx_task_info.soc_id = 0;
    //     tx_task_info.slot_id = slot;
    //     s32Ret = MID_UTIL_CreateDetachThread(PF_AR8030_Task_TX_For_Enter, NULL, NULL);
    //     if(s32Ret < 0)
    //     {
    //         PRINT_ERR("create ARCAST_AR8030_Task_TX fail!\n");
    //         return -1;
    //     }
    // }
    // else {
    //     /* Create ringbuffer for rx */
    //     PF_Parser_Init(MAX_RINGBUF_LEN);

    //     rx_task_info.soc_id = 0;
    //     rx_task_info.slot_id = slot;
    //     s32Ret = MID_UTIL_CreateDetachThread(PF_AR8030_Task_RX, NULL, NULL);
    //     if(s32Ret < 0)
    //     {
    //         PRINT_ERR("create PF_AR8030_Task_RX fail!\n");
    //         return -1;
    //     }
    // }



        tx_task_info.soc_id = 0;
        tx_task_info.slot_id = slot;
        s32Ret = MID_UTIL_CreateDetachThread(PF_AR8030_Task_TX_For_Enter, NULL, NULL);
        if(s32Ret < 0)
        {
            PRINT_ERR("create ARCAST_AR8030_Task_TX fail!\n");
            return -1;
        }
  
        /* Create ringbuffer for rx */
        PF_Parser_Init(MAX_RINGBUF_LEN);

        rx_task_info.soc_id = 0;
        rx_task_info.slot_id = slot;
        s32Ret = MID_UTIL_CreateDetachThread(PF_AR8030_Task_RX, NULL, NULL);
        if(s32Ret < 0)
        {
            PRINT_ERR("create PF_AR8030_Task_RX fail!\n");
            return -1;
        }
    


    start_ms = MID_UTIL_Get_Time_ms();

    while(1) {
        if (signal_exit) {
            break;
        }

        if (is_tx && (g_stAr8030TxThread.status == TASK_STATUS_RUNNING) && (test_time != -1)) {
            now_ms = MID_UTIL_Get_Time_ms();
            if (((now_ms - start_ms)/1000) >= test_time) {
                g_stAr8030TxThread.s32Ar8030TxThreadExit = true;
            }
        }
        else if (is_tx && (g_stAr8030TxThread.status == TASK_STATUS_SHUTDOWN)) {
            now_ms = MID_UTIL_Get_Time_ms();
            printf("####TX total pkt %lu bytes %lu bytes rate %lukbps time:%ds ########\n",
                    tot_tx_pkt_num_g,
                    total_tx_dat_len_g,
                    total_tx_dat_len_g*8/(now_ms - start_ms),
                    ((now_ms - start_ms)/1000));
            printf("####TX payload pkt %lu bytes %lu bytes rate %lukbps time:%ds ########\n",
                    tot_tx_pkt_num_payload_g,
                    total_tx_dat_len_payload_g,
                    total_tx_dat_len_payload_g*8/(now_ms - start_ms),
                    ((now_ms - start_ms)/1000));
            break;
        }
        else if (!is_tx && (g_stAr8030RxThread.status == TASK_STATUS_SHUTDOWN)) {
            now_ms = MID_UTIL_Get_Time_ms();
            printf("####RX total pkt %lu bytes %lu bytes rate %lukbps time:%ds########\n",
                    total_rx_pkt_num_g,
                    total_rx_dat_len_g,
                    total_rx_dat_len_g*8/(now_ms - start_ms),
                    ((now_ms - start_ms)/1000));
            printf("####RX payload pkt %lu bytes %lu bytes rate %lukbps time:%ds########\n",
                    total_rx_pkt_num_payload_g,
                    total_rx_dat_len_payload_g,
                    total_rx_dat_len_payload_g*8/(now_ms - start_ms),
                    ((now_ms - start_ms)/1000));
            break;
        }

        usleep(10);
    }

    if (!is_tx) {
        PF_Parser_Deinit();
    }

    printf("test end, exit!\n");

    exit(0);
}